use clap::Parser;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate rbatis;
extern crate rbdc;
extern crate rbdc_mysql;
use rbatis::rbatis::RBatis;
use rbatis::{executor::Executor, rbdc::datetime::DateTime};
use rbdc_mysql::Driver;
use tokio::{
    runtime::{Builder, Handle, Runtime},
    task,
};
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
    #[arg(long)]
    user: String,

    #[arg(long)]
    password: String,

    #[arg(long)]
    host: String,

    #[arg(long)]
    port: String,

    #[arg(long)]
    database: String,
}

use urlencoding::encode;

//初始化知识库连接
pub async fn init_rbatis(user: String, password: String, host: String, port: String, db: String) {
    let str = format!(
        "mysql://{}:{}@{}:{}/{}",
        &user,
        encode(&password),
        &host,
        &port,
        &db
    );
    //println!("{}",&str);
    RB.link(rbdc_mysql::driver::MysqlDriver {}, &str)
        .await
        .unwrap();
}

lazy_static! {
    pub static ref RB: RBatis = RBatis::new();
}

#[tokio::main]
pub async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    let args = Args::parse();
    init_rbatis(
        args.user.to_owned(),
        args.password.to_owned(),
        args.host.to_owned(),
        args.port.to_owned(),
        args.database.to_owned(),
    )
    .await;

    //输出catalog
    let catalogs = RB.query(&format!("show catalogs"), vec![]).await?;
    let catalogs_arr = catalogs.as_array().unwrap();

    for f in catalogs_arr {
        let catalog_name = f.as_map().unwrap()["CatalogName"].as_str().unwrap();
        if catalog_name == "internal" {
            continue;
        }
        println!("/*show create catalog {} */", &catalog_name);
        let show_sql_result = RB
            .query(&format!("show create catalog {}", &catalog_name), vec![])
            .await
            .unwrap();

        let show_sql_arr = show_sql_result.as_array().unwrap();
        let show_sql_value = &show_sql_arr[0];

        let show_sql = show_sql_value.as_map().unwrap()["CreateCatalog"]
            .as_str()
            .unwrap();
        println!("{}", &show_sql);
    }

    //按数据库循环
    let databases = RB.query("SHOW DATABASES ", vec![]).await?;
    let databases_arr = databases.as_array().unwrap();
    for db in databases_arr {
        let db_name = db.as_map().unwrap()["Database"].as_str().unwrap();
        if db_name == "__internal_schema" || db_name == "information_schema" || db_name == "mysql" {
            continue;
        }
        let mut tx = RB.acquire().await?;
        println!("use {};", &db_name);

        let _ = tx.exec(&format!("use {}", &db_name), vec![]).await?;

        //输出自定义udf
        let functions = tx
            .query(&format!("show full functions in {}", &db_name), vec![])
            .await?;
        let functions_arr = functions.as_array().unwrap();

        for f in functions_arr {
            let function_name = f.as_map().unwrap()["Signature"].as_str().unwrap();
            let show_sql_result = tx
                .query(
                    &format!("show create function {} from {}", &function_name, &db_name),
                    vec![],
                )
                .await
                .unwrap();

            let show_sql_arr = show_sql_result.as_array().unwrap();
            let show_sql_value = &show_sql_arr[0];

            let show_sql = show_sql_value.as_map().unwrap()["Create Function"]
                .as_str()
                .unwrap();
            println!("{}", &show_sql);
        }

        //输出表结构
        let tables = tx
            .query(&format!("show full tables in {}", &db_name), vec![])
            .await?;
        let tables_arr = tables.as_array().unwrap();

        for f in tables_arr {
            let table_name = f.as_map().unwrap()[format!("Tables_in_{}", &db_name).as_str()]
                .as_str()
                .unwrap();
            let table_type = f.as_map().unwrap()[format!("Table_type").as_str()]
                .as_str()
                .unwrap();
            if table_type == "BASE TABLE" {
                println!(
                    "/*{}*/",
                    &format!("show create table {}.{}", &db_name, &table_name)
                );
                match tx
                    .query(
                        &format!("show create table {}.{}", &db_name, &table_name),
                        vec![],
                    )
                    .await
                {
                    Ok(show_sql_result) => {
                        let show_sql_arr = show_sql_result.as_array().unwrap();
                        let show_sql_value = &show_sql_arr[0];
                        let show_sql_row = show_sql_value.as_map().unwrap();
                        let show_sql = { show_sql_row["Create Table"].as_str().unwrap() };
                        println!("{}", &show_sql);
                    }
                    Err(_) => {}
                }
            }
            if table_type == "VIEW" {
                println!(
                    "/*{}*/",
                    &format!(
                        "select * from mv_infos('database'='{}') where Name = '{}'",
                        &db_name, &table_name
                    )
                );
                match tx
                    .query(
                        &format!(
                            "select cast  (QuerySql as varchar) QuerySql from mv_infos('database'='{}') where Name = '{}'",
                            &db_name, &table_name
                        ),
                        vec![],
                    )
                    .await
                {
                    Ok(show_sql_result) => {
                        let show_sql_arr = show_sql_result.as_array().unwrap();
                        if show_sql_arr.len() > 0 {
                            let show_sql_value = &show_sql_arr[0];
                            let show_sql_row = show_sql_value.as_map().unwrap();
                            let show_sql = { show_sql_row["QuerySql"].as_str().unwrap() };
                            println!("{}", &show_sql);
                        }
                    }
                    Err(_) => {}
                }
            }
        }

        //输出router load
        let routine_loads = tx.query("SHOW ALL ROUTINE LOAD", vec![]).await?;
        let routine_load_arr = routine_loads.as_array().unwrap();

        for f in routine_load_arr {
            let routine_load_name = f.as_map().unwrap()["Name"].as_str().unwrap();
            let show_sql_result = tx
                .query(
                    &format!(
                        "show  all create ROUTINE  load  for {}.{}",
                        &db_name, &routine_load_name
                    ),
                    vec![],
                )
                .await
                .unwrap();

            let show_sql_arr = show_sql_result.as_array().unwrap();

            if show_sql_arr.len() > 0 {
                let show_sql_value = &show_sql_arr[0];
                let show_sql_row = show_sql_value.as_map().unwrap();
                let show_sql = {
                    if !show_sql_row["CreateStmt"].is_null() {
                        show_sql_row["CreateStmt"].as_str().unwrap()
                    } else {
                        ""
                    }
                };
                println!("{}", &show_sql);
            }
        }

        tx.commit().await?;
    }

    Ok(())
}
